package com.datou.datouspringmvc.context;

import com.datou.datouspringmvc.annotation.AutoWired;
import com.datou.datouspringmvc.annotation.Controller;
import com.datou.datouspringmvc.annotation.Service;
import com.datou.utils.XMLUtils;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class DatouWebApplicationContext {
    private List<String> classFullPathList = new ArrayList<>();

    public ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();

    private String configLocation; // spring配置文件路径

    public DatouWebApplicationContext(String configLocation) {
        this.configLocation = configLocation;
    }

    public DatouWebApplicationContext() {
    }

    public void init() {
        String basePackage = XMLUtils.getBasePackage(configLocation.split(":")[1]);
        String[] basePackages = basePackage.split(",");
//        System.out.println("basePackage = " + basePackage);
        if(basePackages.length > 0) {
            for (String pack : basePackages) {
                scanPackage(pack);
            }
        }

//        System.out.println("classFullPathList = " + classFullPathList);

        // 将扫描到的类对象注入到容器中
        executeInstance();
        System.out.println("扫描后ioc = " + ioc);

        // 完成注入的bean对象的属性的装配
        executeAutoWired();
        System.out.println("装配后ioc = " + ioc);
    }

    // 创建方法，完成对包的扫描
    public void scanPackage(String packageName) {
//        得到包所在的工作路径【绝对路径】

        // 通过类的加载器，得到指定的包对应的工作路径
        URL url = this.getClass().getClassLoader()
                .getResource("/" + packageName.replaceAll("\\.", "/"));

//        System.out.println("url = " + url);

        File file = new File(url.getFile());
        for(File f : file.listFiles()) {
            if (f.isDirectory()) { // 目录，采用递归处理
                scanPackage(packageName + "." + f.getName());
            } else {
                String classFullPath = packageName + "." + f.getName().replaceAll(".class", "");
                classFullPathList.add(classFullPath);
            }
        }
    }

    // 编写方法，将扫描到的类，在满足条件的情况下，反射到ioc容器中
    public void executeInstance() {
        // 判断是否扫描到该类
        if (classFullPathList.size() == 0) {
            return;
        }

        for (String classFullPath : classFullPathList) {
            try {
                Class<?> aClass = Class.forName(classFullPath);
                if(aClass.isAnnotationPresent(Controller.class)) {
                    String simpleName = aClass.getSimpleName().substring(0, 1).toLowerCase()
                            + aClass.getSimpleName().substring(1);
                    ioc.put(simpleName, aClass.newInstance());
                } else if(aClass.isAnnotationPresent(Service.class)) {
                    String beanName = aClass.getAnnotation(Service.class).value();
                    Object instance = aClass.newInstance();
                    if("".equals(beanName)) {
                        Class<?>[] interfaces = aClass.getInterfaces();
                        for (Class<?> anInterface : interfaces) {
                            beanName = anInterface.getSimpleName().substring(0, 1).toLowerCase()
                                    + anInterface.getSimpleName().substring(1);
                            ioc.put(beanName, instance);
                        }
                    } else {
                        ioc.put(beanName, instance);
                    }

                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    /**
     * 完成对象属性的装配，即@Resource
     */
    public void executeAutoWired() {

        if(ioc.isEmpty()) {
            return;
        }

        for(Map.Entry<String, Object> entry : ioc.entrySet()) {
            String key = entry.getKey();
            Object bean = entry.getValue();
            Field[] declaredFields = bean.getClass().getDeclaredFields();
            for(Field field : declaredFields) {
                if (field.isAnnotationPresent(AutoWired.class)) { // 当前字段是否有AutoWired 注解
                    AutoWired annotation = field.getAnnotation(AutoWired.class);
                    // 关联的bean对象
                    String beanName = annotation.value();
                    if(beanName.isEmpty()) {
                        // 没有指定
                        // 使用类型名的驼峰写法来作为装配对象
                        beanName = field.getType().getSimpleName().substring(0, 1).toLowerCase()
                        + field.getType().getSimpleName().substring(1);
                    }
                    // 从容其中获取该对象
                    Object object = ioc.get(beanName);
                    // 判断该对象是否存在
                    if(object == null) {
                        throw new RuntimeException("ioc 容器中不存在你要装配的bean对象");
                    } else {
                        field.setAccessible(true);
                        try {
                            field.set(bean, object);
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }

    }
}
